using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pay.Core;
using Pay.Data;
using Pay.DTO;
using Pay.IService;
using Pay.TO;

namespace Pay.Service {
    public class MerchantBillService : ServiceBase {
        protected ISettingService _iSettingService;
        protected IBillService _iBillService;
        protected IMerchantService _iMerchantService;
        protected IPaymentService _iPaymentService;
        protected IPayHtmlService _iPayHtmlService;
        protected IPayNotifyService _iPayNotifyService;

        public MerchantBillService(IUnitOfWork iUnitOfWork, ISettingService iSettingService, IBillService iBillService,
                                   IMerchantService iMerchantService, IPaymentService iPaymentService,
                                   IPayHtmlService iPayHtmlService, IPayNotifyService iPayNotifyService)
            : base(iUnitOfWork) {
            _iSettingService = iSettingService;
            _iBillService = iBillService;
            _iMerchantService = iMerchantService;
            _iPaymentService = iPaymentService;
            _iPayHtmlService = iPayHtmlService;
            _iPayNotifyService = iPayNotifyService;
        }

        #region 商户
        private DateTime _billDt;
        private Dictionary<string, Bill> _merchant_accounts;
        public StringBuilder sb = new StringBuilder();

        /// <summary>
        /// 新增商户账务,处理好不要重复新增相同用户的账单
        /// </summary>
        /// <param name="merchant_id"></param>
        /// <returns></returns>
        private void AddMerchantBill2(long merchant_id) {
            sb.AppendLine();
            sb.AppendLine("set @bill_id=null");
            sb.AppendLine("set @balance=null");
            sb.AppendLine("set @out_profit=null");
            sb.AppendLine("set @other_amt=null");
            sb.AppendLine("set @security=null");
            sb.AppendFormat("SELECT @bill_id=Id,@balance=Balance,@out_profit=OutProfit,@other_amt=OtherAmt,@security=Security FROM mc_Bill WHERE MerchantId={0};", merchant_id);
            sb.AppendLine();
            sb.AppendFormat("if @bill_id is NULL");
            sb.AppendLine();
            sb.AppendFormat("BEGIN");
            sb.AppendLine();
            sb.AppendFormat("    INSERT INTO mc_Bill(MerchantId,Balance,Unconfirmed,Deposited,Depositeding,Deposit,Freeze,Security)VALUES ({0},0,0,0,0,0,0,0)", merchant_id);
            sb.AppendLine();
            sb.AppendLine("    set @bill_id = @@identity;");
            sb.AppendLine("    set @balance=0;");
            sb.AppendLine("    set @out_profit=0;");
            sb.AppendLine("    set @other_amt=0;");
            sb.AppendLine("    set @security=0;");
            sb.AppendLine("END");
        }

        /// <summary>
        /// 新增商户账务,处理好不要重复新增相同用户的账单
        /// </summary>
        /// <param name="merchant_id"></param>
        /// <returns></returns>
        private Bill AddMerchantBill(long merchant_id) {
            string key = merchant_id.ToString();
            Bill account;
            if (_merchant_accounts.TryGetValue(key, out account))
                return account;
            account = context.Bills.Where(c => c.MerchantId == merchant_id).FirstOrDefault();
            if (account == null) {
                account = new Bill();
                account.MerchantId = merchant_id;
                context.Bills.Add(account);
                _merchant_accounts.Add(key, account);
            } else {
                _merchant_accounts.Add(key, account);
            }

            return account;
        }
        #endregion

        #region 收款账单
        /// <summary>
        /// 账单
        /// </summary>
        /// <returns></returns>
        /// <param name="charge">charge</param>
        protected void ChargeAccount(Charge charge) {
            _billDt = charge.OrderTime.ToDateTime();
            _merchant_accounts = new Dictionary<string, Bill>();
            if (charge.Type == 2) {
                UpgradeAccount(charge);
            } else {
                //小商户分润
                var profits = charge.Profit.ToObject<List<bind_merchant_item>>();
                foreach (var profit in profits)
                    AddChargeProfitAccount(charge, profit);
                //O单商户分润及签约通道的商户分润
                AddChargeOemMerchantAccount(charge, profits);
                //结算费分润
                if (charge.SettleFee > 0)
                    OemTransfer(charge);
                //收款商户账单
                //目前只有HF的T1快捷要加商户余额
                if (!charge.IsOut && charge.PayInfo.PayChannel == PayChannel.HF && charge.PayInfo.PayType == PayType.Quick)
                    AddChargeMerchantAccount(charge);
                //目前只有HF的T0扫码要加商户余额
                if (charge.IsOut && charge.PayInfo.PayChannel == PayChannel.HF && (charge.PayInfo.PayType == PayType.Native || charge.PayInfo.PayType == PayType.JSPAY || charge.PayInfo.PayType == PayType.SDK))
                    AddChargeMerchantAccount(charge);
            }
        }

        /// <summary>
        /// 小商户分润
        /// </summary>
        /// <param name="charge">Charge.</param>
        /// <param name="profit">Profit.</param>
        private void AddChargeProfitAccount(Charge charge, bind_merchant_item profit) {
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            billDetail.PayInfo = charge.PayInfo;
            billDetail.Status = BillStatus.Finish;
            billDetail.Amount = profit.amount;
            billDetail.BillType = BillType.FeeProfit;

            var merchant = _iMerchantService.Get(profit.merchant_no);
            #region ef
            var account = AddMerchantBill(merchant.id);
            account.Balance += billDetail.Amount;
            if (profit.freeze || account.Freeze)
                account.Unconfirmed += billDetail.Amount;
            else
                account.Deposit += billDetail.Amount;

            billDetail.Bill = account;
            billDetail.Balance = account.Balance;
            context.BillDetails.Add(billDetail);
            #endregion
            #region sql
            //AddMerchantBill2(merchant.id);
            //sb.AppendFormat("SET @balance={0}+@balance;", billDetail.Amount);
            //sb.AppendLine();
            //if (profit.freeze) {
            //	sb.AppendFormat("UPDATE mc_Bill set Unconfirmed=Unconfirmed+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
            //	sb.AppendLine();
            //} else {
            //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
            //	sb.AppendLine();
            //}
            //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
            //	billDetail.CreateTime, charge.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
            //sb.AppendLine();
            #endregion
        }

        /// <summary>
        /// O单商户分润，通道签约商户分润
        /// </summary>
        private void AddChargeOemMerchantAccount(Charge charge, List<bind_merchant_item> profits) {
            var profit = profits.Sum(c => (decimal?)(c.amount)) ?? 0;
            var merchants = _iMerchantService.GetParents(charge.MerchantId);
            //增加高清分润
            #region ef
            if (profit > 0) {
                var oemAccount = AddMerchantBill(charge.MerchantId);
                oemAccount.OutProfit += profit;
                oemAccount.Security += profit;
            }
            #endregion
            #region sql
            //if (profit > 0) {
            //	AddMerchantBill2(charge.MerchantId);
            //	sb.AppendFormat("UPDATE mc_Bill set OutProfit=OutProfit+{0},Security=Security+{0} WHERE id=@bill_id;", profit);
            //	sb.AppendLine();
            //}
            #endregion
            int i = 0;
            decimal fee = charge.Fee;
            //总的高清
            decimal o_amount = profit;
            foreach (var oemer in merchants) {
                decimal amount = 0;
                if (i == 0) {
                    //要向下取整
                    amount = ((fee - charge.MerchantFee) * charge.PayAmount).RoundDown(2) - profit;
                    #region ef
                    if (amount < 0) charge.SubsidyAmount = amount;
                    #endregion
                    #region sql
                    //if (amount < 0) {
                    //	sb.AppendFormat("UPDATE mc_Charge set SubsidyAmount={0} WHERE id={1};", amount, charge.Id);
                    //	sb.AppendLine();
                    //}
                    #endregion
                    o_amount += amount;
                    fee = charge.MerchantFee;
                } else {
                    if (amount <= 0) continue;
                    var oemer_payments = _iMerchantService.GetPayments(oemer.id);
                    var payment = oemer_payments.FirstOrDefault(c => c.payment.channel == charge.PayInfo.PayChannel);
                    //没有设置费率跳过
                    if (payment == null) continue;
                    var settle = payment.settles.First(c => c.settle_type == charge.PayInfo.SettleType && c.code == charge.PayInfo.PayCode);
                    amount = ((fee - settle.fee) * charge.PayAmount);
                    o_amount += amount;
                    fee = settle.fee;
                }
                //当APP的商户已经把分润都完了，就跳过O单商
                if (amount != 0M) {
                    var billDetail = new BillDetail();
                    billDetail.CreateTime = _billDt.ToUnix();
                    billDetail.PayInfo = charge.PayInfo;
                    billDetail.Status = BillStatus.Finish;
                    billDetail.Amount = amount;
                    billDetail.BillType = BillType.FeeProfit;
                    #region ef
                    var account = AddMerchantBill(oemer.id);
                    account.Balance += billDetail.Amount;
                    account.Deposit += billDetail.Amount;
                    billDetail.Bill = account;
                    billDetail.Balance = account.Balance;
                    context.BillDetails.Add(billDetail);
                    #endregion
                    #region sql
                    //AddMerchantBill2(merchant.id);
                    //sb.AppendFormat("SET @balance={0}+@balance;", billDetail.Amount);
                    //sb.AppendLine();
                    //sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
                    //sb.AppendLine();
                    //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
                    //	billDetail.CreateTime, charge.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                    //sb.AppendLine();
                    #endregion
                }
                i++;
            }
            if (fee > 0) {
                //签约通道的商户
                var payments = _iPaymentService.Get();
                //通道成本
                var channel_payment = payments.First(c => c.channel == charge.PayInfo.PayChannel);
                //var channel_settle = channel_payment.settles.First(c => c.settle_type == charge.PayInfo.SettleType && c.code == charge.PayInfo.PayCode);
                decimal amount = 0;
                if (o_amount < 0)
                    //如果分润都分光了，成负数时，用O商成本-平台成本
                    amount = ((charge.MerchantFee - charge.PlatFee) * charge.PayAmount).RoundDown(2);
                else
                    //（总扣费-成本）×交易－O商-O商高清
                    amount = (charge.Fee - charge.PlatFee) * charge.PayAmount - o_amount;
                if (amount > 0) {
                    var billDetail = new BillDetail();
                    billDetail.CreateTime = _billDt.ToUnix();
                    billDetail.PayInfo = charge.PayInfo;
                    billDetail.Status = BillStatus.Finish;
                    billDetail.Amount = amount;
                    billDetail.BillType = BillType.FeeProfit;

                    var merchantId = channel_payment.merchant_id;
                    #region ef
                    var account = AddMerchantBill(merchantId);
                    account.Balance += billDetail.Amount;
                    account.Deposit += billDetail.Amount;
                    billDetail.Bill = account;
                    billDetail.Balance = account.Balance;
                    context.BillDetails.Add(billDetail);
                    #endregion
                    #region sql
                    //AddMerchantBill2(merchantId);
                    //sb.AppendFormat("SET @balance={0}+@balance;", billDetail.Amount);
                    //sb.AppendLine();
                    //sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
                    //sb.AppendLine();
                    //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
                    //	billDetail.CreateTime, charge.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                    //sb.AppendLine();
                    #endregion
                }
            }
        }

        /// <summary>
        /// 收款账单
        /// </summary>
        /// <param name="charge">Charge.</param>
        private void AddChargeMerchantAccount(Charge charge) {
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            billDetail.PayInfo = charge.PayInfo;
            billDetail.Status = BillStatus.Finish;
            billDetail.Amount = charge.Amount;
            billDetail.BillType = BillType.Receipt;

            var merchantId = charge.BindId;
            #region ef
            var account = AddMerchantBill(merchantId.Value);
            account.Balance += billDetail.Amount;
            if (account.Freeze)
                account.Unconfirmed += billDetail.Amount;
            else
                account.Deposit += billDetail.Amount;
            billDetail.Bill = account;
            billDetail.Balance = account.Balance;
            context.BillDetails.Add(billDetail);

            //T1增加高清分润
            var oemAccount = AddMerchantBill(charge.MerchantId);
            oemAccount.OutProfit += billDetail.Amount;
            oemAccount.Security += billDetail.Amount;
            #endregion
            #region sql
            //AddMerchantBill2(merchantId.Value);
            //sb.AppendFormat("SET @balance={0}+@balance;", billDetail.Amount);
            //sb.AppendLine();
            //sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
            //sb.AppendLine();
            //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
            //	billDetail.CreateTime, charge.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
            //sb.AppendLine();

            //AddMerchantBill2(charge.MerchantId);
            //sb.AppendFormat("UPDATE mc_Bill set OutProfit=OutProfit+{0},Security=Security+{0} WHERE id=@bill_id;", billDetail.Amount);
            //sb.AppendLine();
            #endregion
        }

        /// <summary>
        /// 结算费分润
        /// </summary>
        /// <param name="model">Model.</param>
        private void OemTransfer(Charge model) {
            var merchants = _iMerchantService.GetParents(model.MerchantId);
            decimal amount = model.SettleFee;
            var pay_code = model.PayInfo.PayCode;
            int i = 0;
            foreach (var oemer in merchants) {
                decimal profit = 0;
                if (i == 0) {
                    profit = amount - model.MerchantSettle;
                    amount = model.MerchantSettle;
                } else {
                    //如果上级O商没有通道设置跳过
                    var oemer_payments = _iMerchantService.GetPayments(oemer.id);
                    if (oemer_payments.Count == 0) continue;
                    var payment = oemer_payments.FirstOrDefault(c => c.payment.channel == model.PayInfo.PayChannel);
                    var settle = payment.settles.First(c => c.settle_type == model.PayInfo.SettleType && c.code == pay_code);
                    profit = amount - settle.settle;
                    amount = settle.settle;
                }
                if (profit > 0) {
                    var billDetail = new BillDetail();
                    billDetail.CreateTime = _billDt.ToUnix();
                    billDetail.PayInfo = model.PayInfo;
                    billDetail.Amount = profit;
                    billDetail.BillType = BillType.SettleProfit;
                    #region ef
                    var account = AddMerchantBill(oemer.id);
                    account.Balance += profit;
                    if (model.Status == ChargeStatus.Finish) {
                        billDetail.Status = BillStatus.Finish;
                        account.Deposit += profit;
                    } else {
                        billDetail.Status = BillStatus.Proceed;
                        account.Unconfirmed += profit;
                    }
                    billDetail.Bill = account;
                    billDetail.Balance = account.Balance;
                    context.BillDetails.Add(billDetail);
                    #endregion
                    #region sql
                    //AddMerchantBill2(merchant.id);
                    //sb.AppendFormat("SET @balance={0}+@balance;", profit);
                    //sb.AppendLine();
                    //if (model.Status == ChargeStatus.Finish) {
                    //	billDetail.Status = BillStatus.Finish;
                    //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", profit);
                    //	sb.AppendLine();
                    //} else {
                    //	billDetail.Status = BillStatus.Proceed;
                    //	sb.AppendFormat("UPDATE mc_Bill set Unconfirmed=Unconfirmed+{0},Balance=@balance WHERE id=@bill_id;", profit);
                    //	sb.AppendLine();
                    //}
                    //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
                    //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                    //sb.AppendLine();
                    #endregion
                }
                i++;
            }
            //签约通道的商户
            if (amount > 0) {
                var payments = _iPaymentService.Get();
                //通道成本
                var channel_payment = payments.First(c => c.channel == model.PayInfo.PayChannel);
                //var channel_settle = channel_payment.settles.First(c => c.settle_type == model.PayInfo.SettleType && c.code == pay_code);
                decimal profit = amount - model.PlatSettle;
                if (profit > 0) {
                    var billDetail = new BillDetail();
                    billDetail.CreateTime = _billDt.ToUnix();
                    billDetail.PayInfo = model.PayInfo;
                    billDetail.Amount = profit;
                    billDetail.BillType = BillType.SettleProfit;
                    #region ef
                    var account = AddMerchantBill(channel_payment.merchant_id);
                    account.Balance += profit;
                    if (model.Status == ChargeStatus.Finish) {
                        billDetail.Status = BillStatus.Finish;
                        account.Deposit += profit;
                    } else {
                        billDetail.Status = BillStatus.Proceed;
                        account.Unconfirmed += profit;
                    }
                    billDetail.Bill = account;
                    billDetail.Balance = account.Balance;
                    context.BillDetails.Add(billDetail);
                    #endregion
                    #region sql
                    //AddMerchantBill2(channel_payment.merchant_id);
                    //sb.AppendFormat("SET @balance={0}+@balance;", billDetail.Amount);
                    //sb.AppendLine();
                    //if (model.Status == ChargeStatus.Finish) {
                    //	billDetail.Status = BillStatus.Finish;
                    //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
                    //	sb.AppendLine();
                    //} else {
                    //	billDetail.Status = BillStatus.Proceed;
                    //	sb.AppendFormat("UPDATE mc_Bill set Unconfirmed=Unconfirmed+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
                    //	sb.AppendLine();
                    //}
                    //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
                    //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                    //sb.AppendLine();
                    #endregion
                }
            }
        }
        #endregion

        #region 代收
        /// <summary>
        /// 代收-提现账单
        /// </summary>
        /// <param name="dto">Dto.</param>
        protected Transfer AddTransfer(apply_receive dto, TransferStatus status) {
            //验证可提现金额够不够
            var merchant = _iMerchantService.Get(dto.merchant_no);
            var binder = _iMerchantService.Get(dto.bind_no);
            var pay_code = "PAYOFF";
            var binder_payments = _iMerchantService.GetPayments(binder.id);
            var payment = binder_payments.FirstOrDefault(c => c.payment.channel == dto.pay_channel);
            var settle = payment.settles.First(c => c.settle_type == dto.settle_type && c.code == pay_code);
            var pay_name = payment.payment.name;
            var fee = settle.fee;
            decimal amount = decimal.Parse(dto.tran_amount) / 100 + fee;

            Transfer model = new Transfer();
            model.OrderNo = dto.order_no;
            model.ApplyTime = DateTime.Now.ToUnix();
            model.MerchantId = merchant.id;
            model.BindId = binder.id;
            model.TransferAmount = amount - fee;
            model.Status = status;
            model.AccountName = dto.rcv_account_name;
            model.BankName = dto.rcv_bank_name;
            model.AccountNo = dto.rcv_account_no;
            model.IdCard = dto.rcv_id_card;
            model.SettleAmount = fee;
            model.Amount = amount;
            model.Notify = dto.notify;

            var dt = DateTime.Now.ToUnix();
            model.PayInfo = new PayInfo {
                OrderNo = model.OrderNo,
                PayNo = model.OrderNo,
                CreateTime = dt,
                PayChannel = dto.pay_channel,
                PayType = dto.pay_type,
                PayCode = dto.pay_code,
                PayName = pay_name,
                SettleType = dto.settle_type,
                TransactionNo = dto.transaction_no,
                PayTime = dt
            };

            context.Transfers.Add(model);
            return model;
        }
        #endregion

        #region 提现账单
        /// <summary>
        /// 单笔提现账单
        /// </summary>
        /// <returns></returns>
        /// <param name="model">model.</param>
        protected void TransferAccount(Transfer model) {
            _billDt = model.ApplyTime.ToDateTime();
            _merchant_accounts = new Dictionary<string, Bill>();
            MerchantTransfer(model);
            OemTransfer(model);
        }

        private void MerchantTransfer(Transfer model) {
            var merchantId = model.BindId;
            //提现
            var amount = model.Amount;
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            billDetail.PayInfo = model.PayInfo;
            billDetail.Amount = -amount;
            billDetail.BillType = BillType.Deposit;
            #region ef
            var account = AddMerchantBill(merchantId);
            account.Balance -= amount;
            account.Deposit -= amount;
            if (model.Status == TransferStatus.Finish) {
                billDetail.Status = BillStatus.Finish;
                account.Deposited += amount;
            } else {
                billDetail.Status = BillStatus.Proceed;
                account.Depositeding += amount;
            }

            billDetail.Bill = account;
            billDetail.Balance = account.Balance;
            context.BillDetails.Add(billDetail);

            //减于高清分润
            var oemAccount = AddMerchantBill(model.MerchantId);
            oemAccount.OutProfit -= model.Amount;
            oemAccount.Security -= model.Amount;
            #endregion
            #region sql
            //AddMerchantBill2(merchantId);
            //sb.AppendFormat("SET @balance=@balance-{0};", amount);
            //sb.AppendLine();
            //if (model.Status == TransferStatus.Finish) {
            //	billDetail.Status = BillStatus.Finish;
            //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit-{0},Deposited=Deposited+{0},Balance=@balance WHERE id=@bill_id;", amount);
            //	sb.AppendLine();
            //} else {
            //	billDetail.Status = BillStatus.Proceed;
            //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit-{0},Depositeding=Depositeding+{0},Balance=@balance WHERE id=@bill_id;", amount);
            //	sb.AppendLine();
            //}
            //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
            //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
            //sb.AppendLine();

            //AddMerchantBill2(model.MerchantId);
            ////减于高清分润
            //sb.AppendFormat("UPDATE mc_Bill set OutProfit=OutProfit-{0},Security=Security-{0} WHERE id=@bill_id;", model.Amount);
            //sb.AppendLine();
            #endregion
        }

        private void OemTransfer(Transfer model) {
            var merchants = _iMerchantService.GetParents(model.MerchantId);
            decimal amount = model.SettleAmount;
            //结算费是0要跳出
            if (amount == 0) return;
            var pay_code = model.PayInfo.PayCode;
            int i = 0;
            foreach (var oemer in merchants) {
                decimal profit = 0;
                if (i == 0) {
                    profit = amount - model.MerchantSettle;
                    amount = model.MerchantSettle;
                } else {
                    //如果上级O商没有通道设置跳过
                    var oemer_payments = _iMerchantService.GetPayments(oemer.id);
                    if (oemer_payments.Count == 0) continue;
                    var payment = oemer_payments.FirstOrDefault(c => c.payment.channel == model.PayInfo.PayChannel);
                    var settle = payment.settles.First(c => c.settle_type == model.PayInfo.SettleType && c.code == pay_code);
                    profit = amount - settle.settle;
                    amount = settle.settle;
                }
                if (profit > 0) {
                    var billDetail = new BillDetail();
                    billDetail.CreateTime = _billDt.ToUnix();
                    billDetail.PayInfo = model.PayInfo;
                    billDetail.Amount = profit;
                    billDetail.BillType = BillType.SettleProfit;
                    #region ef
                    var account = AddMerchantBill(oemer.id);
                    account.Balance += profit;
                    if (model.Status == TransferStatus.Finish) {
                        billDetail.Status = BillStatus.Finish;
                        account.Deposit += profit;
                    } else {
                        billDetail.Status = BillStatus.Proceed;
                        account.Unconfirmed += profit;
                    }
                    billDetail.Bill = account;
                    billDetail.Balance = account.Balance;
                    context.BillDetails.Add(billDetail);
                    #endregion
                    #region sql
                    //AddMerchantBill2(merchant.id);
                    //sb.AppendFormat("SET @balance=@balance+{0};", profit);
                    //sb.AppendLine();
                    //if (model.Status == TransferStatus.Finish) {
                    //	billDetail.Status = BillStatus.Finish;
                    //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", profit);
                    //	sb.AppendLine();
                    //} else {
                    //	billDetail.Status = BillStatus.Proceed;
                    //	sb.AppendFormat("UPDATE mc_Bill set Unconfirmed=Unconfirmed+{0},Balance=@balance WHERE id=@bill_id;", profit);
                    //	sb.AppendLine();
                    //}
                    //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
                    //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                    //sb.AppendLine();
                    #endregion
                }
                i++;
            }
            //签约通道的商户
            if (amount > 0) {
                var payments = _iPaymentService.Get();
                //通道成本
                var channel_payment = payments.First(c => c.channel == model.PayInfo.PayChannel);
                //var channel_settle = channel_payment.settles.First(c => c.settle_type == model.PayInfo.SettleType && c.code == pay_code);
                decimal profit = amount - model.PlatSettle;
                if (profit > 0) {
                    var billDetail = new BillDetail();
                    billDetail.CreateTime = _billDt.ToUnix();
                    billDetail.PayInfo = model.PayInfo;
                    billDetail.Amount = profit;
                    billDetail.BillType = BillType.SettleProfit;

                    #region ef
                    var account = AddMerchantBill(channel_payment.merchant_id);
                    account.Balance += profit;
                    if (model.Status == TransferStatus.Finish) {
                        billDetail.Status = BillStatus.Finish;
                        account.Deposit += profit;
                    } else {
                        billDetail.Status = BillStatus.Proceed;
                        account.Unconfirmed += profit;
                    }
                    billDetail.Bill = account;
                    billDetail.Balance = account.Balance;
                    context.BillDetails.Add(billDetail);
                    #endregion
                    #region sql
                    //AddMerchantBill2(channel_payment.merchant_id);
                    //sb.AppendFormat("SET @balance=@balance+{0};", profit);
                    //sb.AppendLine();
                    //if (model.Status == TransferStatus.Finish) {
                    //	billDetail.Status = BillStatus.Finish;
                    //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", profit);
                    //	sb.AppendLine();
                    //} else {
                    //	billDetail.Status = BillStatus.Proceed;
                    //	sb.AppendFormat("UPDATE mc_Bill set Unconfirmed=Unconfirmed+{0},Balance=@balance WHERE id=@bill_id;", profit);
                    //	sb.AppendLine();
                    //}
                    //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
                    //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                    //sb.AppendLine();
                    #endregion
                }
            }
        }

        /// <summary>
        /// 已有提现账单，修改状态和余额等
        /// </summary>
        /// <param name="pay_id">Pay identifier.</param>
        public void TransferAccounted(long pay_id) {
            TransferAccounted(new List<long> { pay_id });
        }

        /// <summary>
        /// 已有提现账单，修改状态和余额等
        /// </summary>
        /// <param name="pay_ids">Pay identifiers.</param>
        public void TransferAccounted(List<long> pay_ids) {
            if (pay_ids.Count == 0) return;
            var billDetails = context.BillDetails.Where(c => pay_ids.Contains(c.PayId)).ToList();
            billDetails.DataForEach(billDetail => {
                if (billDetail.Status != BillStatus.Finish) {
                    if (billDetail.BillType == BillType.Deposit) {
                        var amount = -billDetail.Amount;
                        billDetail.Bill.Depositeding -= amount;
                        billDetail.Bill.Deposited += amount;
                    } else if (billDetail.BillType == BillType.SettleProfit) {
                        billDetail.Bill.Unconfirmed -= billDetail.Amount;
                        billDetail.Bill.Deposit += billDetail.Amount;
                    }
                    billDetail.Status = BillStatus.Finish;
                }
            });
        }

        /// <summary>
        /// 已有提现账单，修改状态和余额，还要将新的pay_id更新
        /// </summary>
        /// <param name="old_pay_id">Old pay identifier.</param>
        /// <param name="new_pay_info">New pay info.</param>
        public void TransferAccounted(long old_pay_id, PayInfo new_pay_info) {
            var billDetails = context.BillDetails.Where(c => c.PayId == old_pay_id).ToList();
            billDetails.DataForEach(billDetail => {
                if (billDetail.Status != BillStatus.Finish) {
                    if (billDetail.BillType == BillType.Deposit) {
                        var amount = -billDetail.Amount;
                        billDetail.Bill.Depositeding -= amount;
                        billDetail.Bill.Deposited += amount;
                    } else if (billDetail.BillType == BillType.SettleProfit) {
                        billDetail.Bill.Unconfirmed -= billDetail.Amount;
                        billDetail.Bill.Deposit += billDetail.Amount;
                    }
                    billDetail.Status = BillStatus.Finish;
                }
                billDetail.PayInfo = new_pay_info;
            });
        }
        #endregion

        #region Token提现账单
        /// <summary>
        /// token生成提现账单
        /// </summary>
        /// <param name="model"></param>
        public void TokenTransferAccount(TokenTransfer model) {
            if (model.TransferType == TokenTransferType.Upgrade || model.TransferType == TokenTransferType.Bus) {
                var statistic = context.TokenStatistics.FirstOrDefault(c => c.MerchantId == model.MerchantId);
                if (statistic != null) {
                    if (model.TransferType == TokenTransferType.Upgrade) {
                        statistic.Deposit = (statistic.Deposit ?? 0) - model.TransferAmount;
                        statistic.Depositing = (statistic.Depositing ?? 0) + model.TransferAmount;
                    } else {
                        statistic.BusDeposit = (statistic.BusDeposit ?? 0) - model.TransferAmount;
                        statistic.BusDepositing = (statistic.BusDepositing ?? 0) + model.TransferAmount;
                    }
                    if ((statistic.Deposit.HasValue && statistic.Deposit < 0) || (statistic.BusDeposit.HasValue && statistic.BusDeposit.Value < 0))
                        throw new ServerErrorException("生成账单异常");
                }
            } else {
                _merchant_accounts = new Dictionary<string, Bill>();
                var billDetail = new BillDetail();
                billDetail.CreateTime = DateTime.Now.ToUnix();
                billDetail.PayInfo = model.PayInfo;
                billDetail.Amount = -model.TransferAmount;
                billDetail.BillType = BillType.Deposit;
                billDetail.Status = BillStatus.Proceed;

                var account = AddMerchantBill(model.MerchantId);
                account.Balance -= model.TransferAmount;
                if (model.TransferType == TokenTransferType.Distribution) {
                    account.Deposit -= model.TransferAmount;
                    account.Depositeding += model.TransferAmount;
                } else if (model.TransferType == TokenTransferType.Shop) {
                    account.GoodsDeposit -= model.TransferAmount;
                    account.GoodsDepositing += model.TransferAmount;
                }
                billDetail.Bill = account;
                context.BillDetails.Add(billDetail);
            }
        }
        /// <summary>
        /// token分销、店铺提现成功业务
        /// </summary>
        /// <param name="transfer"></param>
        /// <param name="type"></param>
        public void TokenTransferAccounted(TokenTransfer transfer, TokenTransferType type) {
            var bill = context.Bills.FirstOrDefault(c=>c.MerchantId == transfer.MerchantId);
            if (bill != null) {
                if (type == TokenTransferType.Distribution) {
                    bill.Depositeding -= transfer.TransferAmount;
                    bill.Deposited += transfer.TransferAmount;
                } else if (type == TokenTransferType.Shop) {
                    bill.GoodsDepositing -= transfer.TransferAmount;
                    bill.GoodsDeposited += transfer.TransferAmount;
                }
            }
        }
        /// <summary>
        /// 398升级提现成功业务
        /// </summary>
        /// <param name="model"></param>
        public void TokenTransferAccounted(TokenTransfer model) {
            var statistics = context.TokenStatistics.FirstOrDefault(c => c.MerchantId == model.MerchantId);
            if (statistics != null) {
                if (model.TransferType == TokenTransferType.Upgrade) {
                    statistics.Depositing = (statistics.Depositing ?? 0) - model.TransferAmount;
                    statistics.Deposited = (statistics.Deposited ?? 0) + model.TransferAmount;
                } else if (model.TransferType == TokenTransferType.Bus) {
                    statistics.BusDepositing = (statistics.BusDepositing ?? 0) - model.TransferAmount;
                    statistics.BusDeposited = (statistics.BusDeposited ?? 0) + model.TransferAmount;
                }
            }
        }
        /// <summary>
        /// 审核未通过或者打款失败，回滚提现账单
        /// </summary>
        /// <param name="model"></param>
        public void TokenTransferRefund(TokenTransfer model) {
            if (model.TransferType == TokenTransferType.Distribution) {
                var bill = context.Bills.FirstOrDefault(c => c.MerchantId == model.MerchantId);
                if (bill != null) {
                    bill.Balance += model.TransferAmount;
                    bill.Deposit += model.TransferAmount;
                    bill.Depositeding -= model.TransferAmount;
                    if (bill.Depositeding < 0)
                        throw new ServerErrorException("分润账单异常");
                }
            } else if (model.TransferType == TokenTransferType.Shop) {
                var bill = context.Bills.FirstOrDefault(c => c.MerchantId == model.MerchantId);
                if (bill != null) {
                    bill.Balance += model.TransferAmount;
                    bill.GoodsDeposit += model.TransferAmount;
                    bill.GoodsDepositing -= model.TransferAmount;
                    if (bill.GoodsDepositing < 0)
                        throw new ServerErrorException("店铺账单异常");
                }
            } else if (model.TransferType == TokenTransferType.Upgrade) {
                var statistics = context.TokenStatistics.FirstOrDefault(c => c.MerchantId == model.MerchantId);
                if (statistics != null) {
                    if (model.TransferType == TokenTransferType.Upgrade) {
                        statistics.Depositing = (statistics.Depositing ?? 0) - model.TransferAmount;
                        statistics.Deposit = (statistics.Deposit ?? 0) + model.TransferAmount;
                        if (statistics.Depositing.HasValue && statistics.Depositing.Value < 0)
                            throw new ServerErrorException("398账单异常");
                    } else if (model.TransferType == TokenTransferType.Bus) {
                        statistics.BusDepositing = (statistics.BusDepositing ?? 0) - model.TransferAmount;
                        statistics.BusDeposit = (statistics.BusDeposit ?? 0) + model.TransferAmount;
                        if (statistics.BusDepositing.HasValue && statistics.BusDepositing.Value < 0)
                            throw new ServerErrorException("业绩账单异常");
                    }
                }
            }
        }

        #endregion

        #region 升级分润
        /// <summary>
        /// 升级账单
        /// </summary>
        /// <param name="model"></param>
        private void UpgradeAccount(Charge model) {
            _billDt = model.OrderTime.ToDateTime();
            _merchant_accounts = new Dictionary<string, Bill>();
            var oemer = _iMerchantService.Get(model.MerchantId);
            //如果不分账就跳过
            if (!oemer.trade_outpay) return;
            //升级分润分配
            var profits = model.Profit.ToObject<List<bind_merchant_item>>();
            foreach (var profit in profits)
                AddUpgradeProfitAccount(model, profit);
            decimal total = 0;
            if (profits.Count > 0)
                total = profits.Sum(c => c.amount);
            //0单商获得分润
            decimal money = model.Amount + model.FeeAmount - total;
            if (money > 0)
                AddOemUpgradeMerchantAccount(money, model);
            //扣减O单商手续费
            OemUpgradePayFeeRate(model, total);
            //签约通道费率分润
            AddUpgradeProfitPlatAccount(model);
        }

        /// <summary>
        /// 0单商支出通道手续费
        /// </summary>
        /// <param name="model"></param>
        private void OemUpgradePayFeeRate(Charge model, decimal profit) {
            decimal feeAmount = model.FeeAmount;
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            billDetail.PayInfo = model.PayInfo;
            billDetail.Amount = -feeAmount;
            billDetail.BillType = BillType.Fee;
            billDetail.Status = BillStatus.Finish;
            #region ef
            var account = AddMerchantBill(model.MerchantId);
            //增加高清分润
            if (profit > 0)
                account.OutProfit += profit;
            if (model.PayInfo.PayChannel == PayChannel.SFB) {
                account.OtherAmt -= feeAmount;
                billDetail.Balance = account.OtherAmt;
            } else {
                account.Balance -= feeAmount;
                account.Deposit -= feeAmount;
                //如果有高清要加入代付
                if (profit > 0)
                    account.Security += profit;
                billDetail.Balance = account.Balance;
            }
            billDetail.Bill = account;
            context.BillDetails.Add(billDetail);
            #endregion
            #region sql
            //AddMerchantBill2(model.MerchantId);
            //sb.AppendFormat("SET @out_profit=@out_profit+{0};", profit);
            //sb.AppendLine();
            //if (model.PayInfo.PayChannel == PayChannel.SFB) {
            //	sb.AppendFormat("SET @other_amt=@other_amt-{0};", feeAmount);
            //	sb.AppendLine();
            //	sb.Append("UPDATE mc_Bill set OtherAmt=@other_amt,OutProfit=@out_profit WHERE id=@bill_id;");
            //	sb.AppendLine();
            //	sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@other_amt,@bill_id);",
            //		billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
            //} else {
            //	sb.AppendFormat("SET @balance=@balance-{0};", feeAmount);
            //	sb.AppendLine();
            //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit-{0},Balance=@balance,OutProfit=@out_profit,Security=Security+{1} WHERE id=@bill_id;", feeAmount, profit);
            //	sb.AppendLine();
            //	sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
            //		billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
            //}
            #endregion
        }

        /// <summary>
        /// 0单商获得分润
        /// </summary>
        /// <param name="amount"></param>
        /// <param name="model"></param>
        private void AddOemUpgradeMerchantAccount(decimal amount, Charge model) {
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            billDetail.PayInfo = model.PayInfo;
            billDetail.Amount = amount;
            billDetail.BillType = BillType.UpProfit;
            billDetail.Status = BillStatus.Finish;
            #region ef
            var account = AddMerchantBill(model.MerchantId);
            if (model.PayInfo.PayChannel == PayChannel.SFB) {
                account.OtherAmt += billDetail.Amount;
                billDetail.Balance = account.OtherAmt;
            } else {
                account.Balance += billDetail.Amount;
                if (account.Freeze)
                    account.Unconfirmed += billDetail.Amount;
                else
                    account.Deposit += billDetail.Amount;
                billDetail.Balance = account.Balance;
            }
            billDetail.Bill = account;
            context.BillDetails.Add(billDetail);
            #endregion
            #region sql
            //AddMerchantBill2(model.MerchantId);
            //if (model.PayInfo.PayChannel == PayChannel.SFB) {
            //	sb.AppendFormat("SET @other_amt=@other_amt+{0};", amount);
            //	sb.AppendLine();
            //	sb.Append("UPDATE mc_Bill set OtherAmt=@other_amt WHERE id=@bill_id;");
            //	sb.AppendLine();
            //	sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@other_amt,@bill_id);",
            //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
            //} else {
            //	sb.AppendFormat("SET @balance=@balance+{0};", amount);
            //	sb.AppendLine();
            //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", amount);
            //	sb.AppendLine();
            //	sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
            //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
            //}
            #endregion
        }

        /// <summary>
        /// 小商户获得分润
        /// </summary>
        /// <param name="model"></param>
        /// <param name="profit"></param>
        private void AddUpgradeProfitAccount(Charge model, bind_merchant_item profit) {
            var user = _iMerchantService.Get(profit.merchant_no);
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            billDetail.PayInfo = model.PayInfo;
            billDetail.Amount = profit.amount;
            billDetail.BillType = BillType.UpProfit;
            billDetail.Status = BillStatus.Finish;
            #region ef
            var account = AddMerchantBill(user.id);
            account.Balance += profit.amount;
            if (profit.freeze || account.Freeze)
                account.Unconfirmed += billDetail.Amount;
            else
                account.Deposit += billDetail.Amount;

            billDetail.Bill = account;
            billDetail.Balance = account.Balance;
            context.BillDetails.Add(billDetail);
            #endregion
            #region sql
            //AddMerchantBill2(user.id);
            //sb.AppendFormat("SET @balance=@balance+{0};", profit.amount);
            //sb.AppendLine();
            //if (!profit.freeze) {
            //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
            //	sb.AppendLine();
            //} else {
            //	sb.AppendFormat("UPDATE mc_Bill set Unconfirmed=Unconfirmed+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
            //	sb.AppendLine();
            //}
            //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
            //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
            //sb.AppendLine();
            #endregion
        }

        /// <summary>
        /// 通道签约商户分润
        /// </summary>
        private void AddUpgradeProfitPlatAccount(Charge charge) {
            if (charge.FeeAmount > 0) {
                //签约通道的商户
                var payments = _iPaymentService.Get();
                //通道成本
                var channel_payment = payments.First(c => c.channel == charge.PayInfo.PayChannel);
                //var channel_settle = channel_payment.settles.First(c => c.settle_type == charge.PayInfo.SettleType && c.code == charge.PayInfo.PayCode);
                //签约商户
                var pol_merchant = _iMerchantService.Get(channel_payment.merchant_id);
                //如果签约商户有设置，直接用O商户的成本
                merchant_payment_dto pol_payment = null;
                var pol_merchant_payments = _iMerchantService.GetPayments(pol_merchant.id);
                if (pol_merchant_payments.Count > 0)
                    pol_payment = pol_merchant_payments.First(c => c.payment_id == channel_payment.id);
                else {
                    var oemer = _iMerchantService.Get(charge.MerchantId);
                    var oemer_payments = _iMerchantService.GetPayments(oemer.id);
                    var payment = oemer_payments.First(c => c.payment_id == channel_payment.id);
                    pol_payment = payment;
                }
                var pol_settle = pol_payment.settles.First(c => c.settle_type == charge.PayInfo.SettleType);
                var amount = (pol_settle.fee - charge.PlatFee) * charge.PayAmount;
                if (amount > 0) {
                    var billDetail = new BillDetail();
                    billDetail.CreateTime = _billDt.ToUnix();
                    billDetail.PayInfo = charge.PayInfo;
                    billDetail.Status = BillStatus.Finish;
                    billDetail.Amount = amount;
                    billDetail.BillType = BillType.FeeProfit;

                    var merchantId = channel_payment.merchant_id;
                    #region ef
                    var account = AddMerchantBill(merchantId);
                    account.Balance += billDetail.Amount;
                    account.Deposit += billDetail.Amount;

                    billDetail.Bill = account;
                    billDetail.Balance = account.Balance;
                    context.BillDetails.Add(billDetail);
                    #endregion
                    #region sql
                    //AddMerchantBill2(merchantId);
                    //sb.AppendFormat("SET @balance=@balance+{0};", billDetail.Amount);
                    //sb.AppendLine();
                    //sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
                    //sb.AppendLine();
                    //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
                    //	billDetail.CreateTime, charge.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                    //sb.AppendLine();
                    #endregion
                }
            }
        }
        #endregion

        #region 商城账单
        /// <summary>
        /// 商城账单
        /// </summary>
        /// <param name="charge">Charge.</param>
        /// <param name="orders">Orders.</param>
        protected void MallMerchantAccount(Charge charge, List<order_dto> orders) {
            _billDt = charge.OrderTime.ToDateTime();
            _merchant_accounts = new Dictionary<string, Bill>();
            var oemer = _iMerchantService.Get(charge.MerchantId);
            //不分账跳过
            if (!oemer.trade_outpay) return;
            //通道成本
            var payments = _iPaymentService.Get();
            var channel_payment = payments.First(c => c.channel == charge.PayInfo.PayChannel);
            //var channel_settle = channel_payment.settles.First(c => c.settle_type == charge.PayInfo.SettleType && c.code == charge.PayInfo.PayCode);
            foreach (var order in orders) {
                //积分抵扣金额或分销
                //var seller = _iMerchantService.Get(order.merchant_id);
                foreach (var bind in order.binds) {
                    AddMallProfitAccount(charge, order, bind);
                }
                //卖家货款
                AddSellerAccount(charge, order);
                //O商手续费,只能把APP支付的金额加入高清，积分不部分不可以加入
                AddOemMerchantAccount(charge, order);
            }
            //平台成本抽佣金额
            if (charge.PayAmount > 0) {
                var platformFeeAmount = charge.PayAmount * (charge.MerchantFee - charge.PlatFee);
                if (platformFeeAmount > 0)
                    AddMallMerchantAccount(charge, platformFeeAmount, channel_payment.merchant_id);
            }
        }
        /// <summary>
        /// 跨境电商账单
        /// </summary>
        /// <param name="charge">Charge.</param>
        /// <param name="orders">Orders.</param>
        protected void OverSeasMallAccount(Charge charge, List<order_dto> orders) {
            decimal plt_amount = 0;
            _billDt = charge.OrderTime.ToDateTime();
            _merchant_accounts = new Dictionary<string, Bill>();
            #region version1.0
            /*
				foreach (var order in orders) {
				//order.binds包含【分销用户】
				foreach (var bind in order.binds) {
					AddMallProfitAccount(charge, order, bind);
				}
				//卖家货款
				AddSellerAccount(charge, order);
				amount = order.order_items.Sum(c => c.unit_price* c.quantity);
				//平台手续费
				plt_amount = (amount* 1 / 100).RoundUp(2);
				if (plt_amount > 0)
					AddMallMerchantAccount(charge, plt_amount, 1);
				//分销商手续费
				if (order.distribution_id.HasValue) {
					dis_amount = plt_amount;
					AddDistributeAccount(charge, order, dis_amount);
				}
				//oem手续费
				oem_amount = order.fee_amount - plt_amount - dis_amount;
				AddOemFeeAccount(charge, order, oem_amount)
						*/
            #endregion
            foreach (var order in orders) {
                //卖家货款
                AddSellerAccount(charge, order);
                //平台毛利
                plt_amount = order.binds.Where(c => c.is_plat).Sum(c => c.amount);
                AddMallMerchantAccount(charge, plt_amount, 1);
                //分销收益
                var disBinds = order.binds.Where(c => c.is_plat == false);
                foreach (var bind in disBinds) {
                    AddMallProfitAccount(charge, order, bind);
                }
            }
        }
        /// <summary>
        /// H5商城支付
        /// </summary>
        /// <param name="charge">Charge.</param>
        /// <param name="orders">Orders.</param>
        protected void H5MallAccount(Charge charge, List<order_dto> orders) {
            decimal plt_amount = 0;
            _billDt = charge.OrderTime.ToDateTime();
            _merchant_accounts = new Dictionary<string, Bill>();
            foreach (var order in orders) {
                //卖家货款
                AddSellerAccount(charge, order);
                //平台毛利
                plt_amount = order.pay_amount - order.amount;
                AddMallMerchantAccount(charge, plt_amount, 1);
            }
        }
        /// <summary>
        /// 分销分润或积分抵扣
        /// </summary>
        /// <param name="charge">Charge.</param>
        /// <param name="profit">Profit.</param>
        private void AddMallProfitAccount(Charge charge, order_dto order, bind_merchant_item profit) {
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            if (charge.PayId.HasValue)
                billDetail.PayId = charge.PayId.Value;
            else
                billDetail.PayInfo = charge.PayInfo;
            billDetail.Amount = profit.amount;
            billDetail.BillType = BillType.Distribution;
            if (profit.amount < 0)
                billDetail.BillType = BillType.IntPay;
            if (order.status == OrderStatus.Finish)
                billDetail.Status = BillStatus.Finish;
            else
                billDetail.Status = BillStatus.Proceed;

            var merchant = _iMerchantService.Get(profit.merchant_no);
            #region ef
            var account = AddMerchantBill(merchant.id);
            account.Balance += billDetail.Amount;
            //积分的只减冻结
            if (profit.amount < 0)
                account.Unconfirmed += billDetail.Amount;
            else {
                if (order.status == OrderStatus.Finish)
                    account.Deposit += billDetail.Amount;
                else
                    account.Unconfirmed += billDetail.Amount;
            }
            billDetail.Bill = account;
            billDetail.Balance = account.Balance;
            context.BillDetails.Add(billDetail);
            #endregion
        }

        /// <summary>
        /// 平台收入
        /// </summary>
        /// <param name="model">Model.</param>
        /// <param name="amount">Amount.</param>
        /// <param name="merchant_id">Merchant identifier.</param>
        private void AddMallMerchantAccount(Charge model, decimal amount, long merchant_id = 0) {
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            if (model.PayId.HasValue)
                billDetail.PayId = model.PayId.Value;
            else
                billDetail.PayInfo = model.PayInfo;
            billDetail.Amount = amount;
            billDetail.BillType = BillType.FeeProfit;
            if (model.Status == ChargeStatus.Finish)
                billDetail.Status = BillStatus.Finish;
            else
                billDetail.Status = BillStatus.Proceed;
            #region ef
            var account = AddMerchantBill(merchant_id > 0 ? merchant_id : model.MerchantId);
            account.Balance += billDetail.Amount;
            account.Unconfirmed += billDetail.Amount;

            billDetail.Bill = account;
            billDetail.Balance = account.Balance;
            context.BillDetails.Add(billDetail);
            #endregion
        }

        /// <summary>
        /// 卖家货款
        /// </summary>
        private void AddSellerAccount(Charge charge, order_dto order) {
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            if (charge.PayId.HasValue)
                billDetail.PayId = charge.PayId.Value;
            else
                billDetail.PayInfo = charge.PayInfo;
            billDetail.Amount = order.amount;
            billDetail.BillType = BillType.Mall;
            if (order.status == OrderStatus.Finish)
                billDetail.Status = BillStatus.Finish;
            else
                billDetail.Status = BillStatus.Proceed;
            #region ef
            var account = AddMerchantBill(order.merchant_id);
            account.Balance += billDetail.Amount;
            if (order.status == OrderStatus.Finish)
                account.Deposit += billDetail.Amount;
            else
                account.Unconfirmed += billDetail.Amount;
            billDetail.Bill = account;
            billDetail.Balance = account.Balance;
            context.BillDetails.Add(billDetail);
            #endregion
        }

        /// <summary>
        /// o商收入
        /// </summary>
        /// <param name="model">Model.</param>
        /// <param name="order">订单.</param>
        private void AddOemMerchantAccount(Charge model, order_dto order) {
            decimal o_fee = 0M, o_app_fee = 0M;
            if (order.pay_amount > 0) o_app_fee = order.pay_amount * (order.fee - model.PlatFee);
            //积分的－－负负正
            var int_bind = order.binds.FirstOrDefault(c => c.amount < 0);
            if (int_bind != null) o_fee = Math.Abs(int_bind.amount) * order.fee;
            #region ef
            var account = AddMerchantBill(model.MerchantId);
            if (order.pay_amount > 0) {
                if (order.pay_amount <= 1)
                    account.OutProfit += order.pay_amount * (1M - order.fee);
                else
                    account.OutProfit += (order.pay_amount * (1M - order.fee)).RoundUp(2);
            }
            #endregion
            #region sql
            //AddMerchantBill2(model.MerchantId);
            //if (order.pay_amount > 0) {
            //	if (order.pay_amount <= 1) {
            //		sb.AppendFormat("UPDATE mc_Bill set OutProfit=OutProfit+{0} WHERE id=@bill_id;", order.pay_amount * (1M - order.fee));
            //		sb.AppendLine();
            //	} else {
            //		sb.AppendFormat("UPDATE mc_Bill set OutProfit=OutProfit+{0} WHERE id=@bill_id;", (order.pay_amount * (1M - order.fee)).RoundUp(2));
            //		sb.AppendLine();
            //	}
            //}
            #endregion
            if (order.fee_amount > 0) {
                //O商积分手续费,开始有些数据异常，积分的手续费收入没有算，所以加手续费的判断
                if (o_fee != 0 && (order.amount + order.fee_amount) * order.fee == order.fee_amount) {
                    var billDetail = new BillDetail();
                    billDetail.CreateTime = _billDt.ToUnix();
                    billDetail.PayInfo = model.PayInfo;
                    billDetail.Amount = o_fee;
                    billDetail.BillType = BillType.OemIntTradeFee;
                    if (order.status == OrderStatus.Finish)
                        billDetail.Status = BillStatus.Finish;
                    else
                        billDetail.Status = BillStatus.Proceed;
                    #region ef
                    account.Balance += billDetail.Amount;
                    if (order.status == OrderStatus.Finish)
                        account.Deposit += billDetail.Amount;
                    else
                        account.Unconfirmed += billDetail.Amount;
                    billDetail.Balance = account.Balance;
                    billDetail.Bill = account;
                    context.BillDetails.Add(billDetail);
                    #endregion
                    #region sql
                    //sb.AppendFormat("SET @balance=@balance+{0};", billDetail.Amount);
                    //sb.AppendLine();
                    //if (order.status == OrderStatus.Finish) {
                    //	sb.AppendFormat("UPDATE mc_Bill set Deposit=Deposit+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
                    //	sb.AppendLine();
                    //} else {
                    //	sb.AppendFormat("UPDATE mc_Bill set Unconfirmed=Unconfirmed+{0},Balance=@balance WHERE id=@bill_id;", billDetail.Amount);
                    //	sb.AppendLine();
                    //}
                    //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@balance,@bill_id);",
                    //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                    //sb.AppendLine();
                    #endregion
                }
                //支付的手续费
                if (o_app_fee != 0) {
                    var billDetail = new BillDetail();
                    billDetail.CreateTime = _billDt.ToUnix();
                    billDetail.PayInfo = model.PayInfo;
                    billDetail.Amount = o_app_fee;
                    billDetail.BillType = BillType.OemTradeFee;
                    if (order.status == OrderStatus.Finish)
                        billDetail.Status = BillStatus.Finish;
                    else
                        billDetail.Status = BillStatus.Proceed;
                    #region ef
                    account.OtherAmt += billDetail.Amount;
                    billDetail.Balance = account.OtherAmt;
                    billDetail.Bill = account;
                    context.BillDetails.Add(billDetail);
                    #endregion
                    #region sql
                    //sb.AppendFormat("SET @other_amt=@other_amt+{0};", billDetail.Amount);
                    //sb.AppendLine();
                    //sb.Append("UPDATE mc_Bill set OtherAmt=@other_amt WHERE id=@bill_id;");
                    //sb.AppendLine();
                    //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@other_amt,@bill_id);",
                    //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                    //sb.AppendLine();
                    #endregion
                }
            }
            //OEM的费率成本
            if (order.pay_amount > 0) {
                var oem_fee = (order.pay_amount * model.MerchantFee);
                var billDetail = new BillDetail();
                billDetail.CreateTime = _billDt.ToUnix();
                billDetail.PayInfo = model.PayInfo;
                billDetail.Amount = -oem_fee;
                billDetail.BillType = BillType.Fee;
                if (order.status == OrderStatus.Finish)
                    billDetail.Status = BillStatus.Finish;
                else
                    billDetail.Status = BillStatus.Proceed;
                #region ef
                account.OtherAmt += billDetail.Amount;
                billDetail.Balance = account.OtherAmt;
                billDetail.Bill = account;
                context.BillDetails.Add(billDetail);
                #endregion
                #region sql
                //sb.AppendFormat("SET @other_amt=@other_amt-{0};", oem_fee);
                //sb.AppendLine();
                //sb.Append("UPDATE mc_Bill set OtherAmt=@other_amt WHERE id=@bill_id;");
                //sb.AppendLine();
                //sb.AppendFormat("INSERT INTO mc_BillDetail(CreateTime,PayId,Status,Amount,BillType,Balance,BillId)VALUES ({0},{1},{2},{3},{4},@other_amt,@bill_id);",
                //	billDetail.CreateTime, model.PayId, (int)billDetail.Status, billDetail.Amount, (int)billDetail.BillType);
                //sb.AppendLine();
                #endregion
            }
        }
        /// <summary>
        /// Oem手续费
        /// </summary>
        /// <param name="model">Model.</param>
        /// <param name="order">Order.</param>
        /// <param name="amount">Amount.</param>
        private void AddOemFeeAccount(Charge model, order_dto order, decimal amount) {
            var account = AddMerchantBill(model.MerchantId);
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            billDetail.PayInfo = model.PayInfo;
            billDetail.Amount = amount;
            billDetail.BillType = BillType.Fee;
            if (order.status == OrderStatus.Finish)
                billDetail.Status = BillStatus.Finish;
            else
                billDetail.Status = BillStatus.Proceed;
            account.Balance += billDetail.Amount;
            if (order.status == OrderStatus.Finish)
                account.Deposit += billDetail.Amount;
            else
                account.Unconfirmed += billDetail.Amount;
            billDetail.Balance = account.Balance;
            billDetail.Bill = account;
            context.BillDetails.Add(billDetail);
        }
        /// <summary>
        /// 分销商手续费
        /// </summary>
        /// <param name="model">Model.</param>
        /// <param name="order">Order.</param>
        /// <param name="amount">Amount.</param>
        private void AddDistributeAccount(Charge model, order_dto order, decimal amount) {
            var account = AddMerchantBill(order.distribution_id.Value);
            var billDetail = new BillDetail();
            billDetail.CreateTime = _billDt.ToUnix();
            billDetail.PayInfo = model.PayInfo;
            billDetail.Amount = amount;
            billDetail.BillType = BillType.Fee;
            if (order.status == OrderStatus.Finish)
                billDetail.Status = BillStatus.Finish;
            else
                billDetail.Status = BillStatus.Proceed;
            account.Balance += billDetail.Amount;
            if (order.status == OrderStatus.Finish)
                account.Deposit += billDetail.Amount;
            else
                account.Unconfirmed += billDetail.Amount;
            billDetail.Balance = account.Balance;
            billDetail.Bill = account;
            context.BillDetails.Add(billDetail);
        }

        /// <summary>
        /// 资金解冻
        /// </summary>
        /// <param name="order"></param>
        protected void MallAccountDeblock(Data.Order order) {
            var billDetails = context.Profits.Where(c => c.OrderId == order.Id).ToList();
            foreach (var billDetail in billDetails) {
                if (billDetail.BillStatus == BillStatus.Finish || billDetail.BillStatus == BillStatus.Cancel)
                    continue;
                billDetail.BillStatus = BillStatus.Finish;
                if (billDetail.IsBus) {
                    var bill = context.TokenStatistics.FirstOrDefault(c=>c.MerchantId == billDetail.MerchantId);
                    bill.FrozenBusProfit = (bill.FrozenBusProfit ?? 0) - billDetail.Amount;
                    bill.BusDeposit = (bill.BusDeposit ?? 0) + billDetail.Amount;
                } else {
                    var bill = context.Bills.FirstOrDefault(c => c.MerchantId == billDetail.MerchantId);
                    if (billDetail.BillType == BillType.Distribution) {
                        bill.Unconfirmed -= billDetail.Amount;
                        bill.Deposit += billDetail.Amount;
                    } else if (billDetail.BillType == BillType.Mall) {
                        bill.GoodsUnconfirmed -= billDetail.Amount;
                        bill.GoodsDeposit += billDetail.Amount;
                    }
                }
            }
        }
        /// <summary>
        /// 商城退货/退款
        /// </summary>
        /// <param name="order_id"></param>
        /// <param name="amount"></param>
        protected void MallRefundAccount(long order_id, decimal amount) {
            if (amount == 0)
                return;
            var bills = new List<BillDetail>();
            var time = DateTime.Now.ToUnix();
            var billDetails = context.Profits.Where(c => c.OrderId == order_id).ToList();
            foreach (var billDetail in billDetails) {
                if (billDetail.BillStatus == BillStatus.Cancel) continue;
                billDetail.BillStatus = BillStatus.Cancel;
                if (billDetail.IsBus) {
                    var bill = context.TokenStatistics.FirstOrDefault(c=>c.MerchantId == billDetail.MerchantId);
                    bill.FrozenBusProfit = (bill.FrozenBusProfit ?? 0) - billDetail.Amount;
                } else {
                    var bill = context.Bills.FirstOrDefault(c => c.MerchantId == billDetail.MerchantId);
                    if (billDetail.BillType == BillType.Distribution) {
                        bill.Unconfirmed -= billDetail.Amount;
                        bill.Balance -= billDetail.Amount;
                    } else if (billDetail.BillType == BillType.Mall) {
                        bill.GoodsUnconfirmed -= amount;
                        bill.Balance -= amount;
                    }
                }
            }
        }
        #endregion
    }
}